package com.nn.smart.bus.commons.tools.utils;

import org.apache.commons.lang3.StringUtils;

import java.io.Serializable;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.util.Date;
import java.util.Hashtable;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * 身份证号工具
 *
 * @author nanning
 * @date 2019/9/7 13:11
 */
public class IdentityNoUtils implements Serializable {

    /**
     * 15位身份证号
     */
    private static final Integer FIFTEEN_ID_CARD = 15;
    /**
     * 18位身份证号
     */
    private static final Integer EIGHTEEN_ID_CARD = 18;
    /**
     * 数字格式校验
     */
    private static Pattern NUMBER_PATTERN = Pattern.compile("[0-9]*");
    /**
     * 日期格式校验
     */
    private static Pattern DATE_PATTERN = Pattern.compile("^((\\d{2}(([02468][048])|([13579][26]))[\\-\\/\\s]?((((0?[13578])|(1[02]))[\\-\\/\\s]?((0?[1-9])|([1-2][0-9])|(3[01])))|(((0?[469])|(11))[\\-\\/\\s]?((0?[1-9])|([1-2][0-9])|(30)))|(0?2[\\-\\/\\s]?((0?[1-9])|([1-2][0-9])))))|(\\d{2}(([02468][1235679])|([13579][01345789]))[\\-\\/\\s]?((((0?[13578])|(1[02]))[\\-\\/\\s]?((0?[1-9])|([1-2][0-9])|(3[01])))|(((0?[469])|(11))[\\-\\/\\s]?((0?[1-9])|([1-2][0-9])|(30)))|(0?2[\\-\\/\\s]?((0?[1-9])|(1[0-9])|(2[0-8]))))))(\\s(((0?[0-9])|([1-2][0-3]))\\:([0-5]?[0-9])((\\s)|(\\:([0-5]?[0-9])))))?$");
    /**
     * 18位身份证中最后一位校验码
     */
    private final static char[] VERIFY_CODE = {'1', '0', 'X', '9', '8', '7', '6', '5', '4', '3', '2'};
    /**
     * 18位身份证中，各个数字的生成校验码时的权值
     */
    private final static int[] VERIFY_CODE_WEIGHT = {7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2};

    /**
     * 根据身份证号获取性别 0女；1男
     *
     * @param IDCard 完整身份证号码
     * @return java.lang.String
     * @author nanning
     * @date 2019/9/20 14:26
     */
    public static String getSex(String IDCard) {
        if (StringUtils.isNotBlank(IDCard)) {
            if (IDCard.length() == FIFTEEN_ID_CARD) {
                if (Integer.parseInt(IDCard.substring(14, 15)) % 2 == 0) {
                    return sexEnum.FEMALE.value;
                } else {
                    return sexEnum.MALE.value;
                }
            } else if (IDCard.length() == EIGHTEEN_ID_CARD) {
                if (Integer.parseInt(IDCard.substring(16).substring(0, 1)) % 2 == 0) {
                    return sexEnum.FEMALE.value;
                } else {
                    return sexEnum.MALE.value;
                }
            }
        }
        return null;
    }

    /**
     * 根据身份证号获取年龄
     *
     * @param IDCard 完整身份证号码
     * @return java.lang.Integer
     * @author nanning
     * @date 2019/9/20 14:26
     */
    public static Integer getAge(String IDCard) {
        int age;
        LocalDate now = LocalDate.now();
        int nowYear = now.getYear();
        int nowMonth = now.getMonthValue();
        int cardYear = 0;
        int cardMonth = 0;
        if (StringUtils.isNotBlank(IDCard) && isValid(IDCard)) {
            if (IDCard.length() == FIFTEEN_ID_CARD) {
                // 身份证上的年份(15位身份证为1980年前的)
                String uyear = "19" + IDCard.substring(6, 8);
                cardYear = Integer.parseInt(uyear);
                // 身份证上的月份
                String uyue = IDCard.substring(8, 10);
                cardMonth = Integer.parseInt(uyue);
            } else if (IDCard.length() == EIGHTEEN_ID_CARD) {
                // 身份证上的年份
                String year = IDCard.substring(6).substring(0, 4);
                cardYear = Integer.parseInt(year);
                // 身份证上的月份
                String yue = IDCard.substring(10).substring(0, 2);
                cardMonth = Integer.parseInt(yue);
            }
        }
        // 当前月份大于用户出身的月份表示已过生日
        if (cardMonth <= nowMonth) {
            age = nowYear - cardYear + 1;
            // 当前用户还没过生
        } else {
            age = nowYear - cardYear;
        }
        return age;
    }

    /**
     * 根据身份证号获取出生日期
     *
     * @param IDCard 完整身份证号码
     * @return java.lang.String
     * @author nanning
     * @date 2019/9/20 14:26
     */
    public static String getBirthday(String IDCard) {
        String year = "";
        String month = "";
        String day = "";
        if (StringUtils.isNotBlank(IDCard)) {
            //15位身份证号
            if (IDCard.length() == FIFTEEN_ID_CARD) {
                // 身份证上的年份(15位身份证为1980年前的)
                year = "19" + IDCard.substring(6, 8);
                //身份证上的月份
                month = IDCard.substring(8, 10);
                //身份证上的日期
                day = IDCard.substring(10, 12);
                //18位身份证号
            } else if (IDCard.length() == EIGHTEEN_ID_CARD) {
                // 身份证上的年份
                year = IDCard.substring(6).substring(0, 4);
                // 身份证上的月份
                month = IDCard.substring(10).substring(0, 2);
                //身份证上的日期
                day = IDCard.substring(12).substring(0, 2);
            }
        }
        return year + "-" + month + "-" + day;
    }

    /**
     * 身份证验证是否有效
     *
     * @param id 号码内容
     * @return boolean
     * @author
     * @date
     */
    public static boolean isValid(String id) {
        Boolean validResult = true;
        //校验长度只能为15或18
        int len = id.length();
        if (len != FIFTEEN_ID_CARD && len != EIGHTEEN_ID_CARD) {
            validResult = false;
        }
        //校验生日
        if (!validDate(id)) {
            validResult = false;
        }
        return validResult;
    }

    /**
     * 校验生日
     *
     * @param id
     * @return
     */
    private static boolean validDate(String id) {
        try {
            String birth = id.length() == FIFTEEN_ID_CARD ? "19" + id.substring(6, 12) : id.substring(6, 14);
            SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");
            Date birthDate = sdf.parse(birth);
            if (!birth.equals(sdf.format(birthDate))) {
                return false;
            }
        } catch (ParseException e) {
            return false;
        }
        return true;
    }

    /**
     * 验证身份证号码，验证通过返回null
     *
     * @param idStr 完整身份证号码
     * @return java.lang.String
     * @author nanning
     * @date 2019/9/20 14:26
     */
    public static String IdentityNoVerification(String idStr) {
        String iDCardNo = null;
        //判断号码的长度 15位或18位
        if (idStr.length() != FIFTEEN_ID_CARD && idStr.length() != EIGHTEEN_ID_CARD) {
            return "身份证号码长度应该为15位或18位";
        }
        if (idStr.length() == EIGHTEEN_ID_CARD) {
            iDCardNo = idStr.substring(0, 17);
        } else if (idStr.length() == FIFTEEN_ID_CARD) {
            iDCardNo = idStr.substring(0, 6) + "19" + idStr.substring(6, 15);
        }
        if (isStrNum(iDCardNo) == false) {
            return "身份证15位号码都应为数字;18位号码除最后一位外,都应为数字";
        }
        //判断出生年月
        int year = Integer.parseInt(iDCardNo.substring(6, 10));
        String strMonth = iDCardNo.substring(10, 12);
        String strDay = iDCardNo.substring(12, 14);

        String birthDay = year + "-" + strMonth + "-" + strDay;
        if (isStrDate(birthDay) == false) {
            return "身份证生日无效";
        }
        LocalDate now = LocalDate.now();
        if ((now.getYear() - year) > 150 || now.isBefore(LocalDate.parse(birthDay))) {
            return "身份证生日不在有效范围";
        }
        int month = Integer.parseInt(strMonth);
        if (month > 12 || month == 0) {
            return "身份证月份无效";
        }
        int day = Integer.parseInt(strDay);
        if (day > 31 || day == 0) {
            return "身份证日期无效";
        }
        //判断地区码
        Hashtable h = GetAreaCode();
        if (h.get(iDCardNo.substring(0, 2)) == null) {
            return "身份证地区编码错误";
        }
        //判断最后一位
        int theLastOne = 0;
        for (int i = 0; i < 17; i++) {
            theLastOne = theLastOne + Integer.parseInt(String.valueOf(iDCardNo.charAt(i))) * VERIFY_CODE_WEIGHT[i];
        }
        int modValue = theLastOne % 11;
        char strVerifyCode = VERIFY_CODE[modValue];
        iDCardNo = iDCardNo + strVerifyCode;
        if (idStr.length() == EIGHTEEN_ID_CARD && !iDCardNo.equals(idStr)) {
            return "身份证无效，不是合法的身份证号码";
        }
        return null;
    }

    /**
     * 地区代码
     *
     * @return Hashtable
     */
    private static Hashtable GetAreaCode() {
        Hashtable<String, String> hashtable = new Hashtable<>();
        hashtable.put("11", "北京");
        hashtable.put("12", "天津");
        hashtable.put("13", "河北");
        hashtable.put("14", "山西");
        hashtable.put("15", "内蒙古");
        hashtable.put("21", "辽宁");
        hashtable.put("22", "吉林");
        hashtable.put("23", "黑龙江");
        hashtable.put("31", "上海");
        hashtable.put("32", "江苏");
        hashtable.put("33", "浙江");
        hashtable.put("34", "安徽");
        hashtable.put("35", "福建");
        hashtable.put("36", "江西");
        hashtable.put("37", "山东");
        hashtable.put("41", "河南");
        hashtable.put("42", "湖北");
        hashtable.put("43", "湖南");
        hashtable.put("44", "广东");
        hashtable.put("45", "广西");
        hashtable.put("46", "海南");
        hashtable.put("50", "重庆");
        hashtable.put("51", "四川");
        hashtable.put("52", "贵州");
        hashtable.put("53", "云南");
        hashtable.put("54", "西藏");
        hashtable.put("61", "陕西");
        hashtable.put("62", "甘肃");
        hashtable.put("63", "青海");
        hashtable.put("64", "宁夏");
        hashtable.put("65", "新疆");
        hashtable.put("71", "台湾");
        hashtable.put("81", "香港");
        hashtable.put("82", "澳门");
        hashtable.put("91", "国外");
        return hashtable;
    }

    /**
     * 判断字符串是否为数字
     *
     * @param str
     * @return boolean
     * @author nanning
     * @date 2019/9/20 13:58
     */
    private static boolean isStrNum(String str) {
        Matcher isNum = NUMBER_PATTERN.matcher(str);
        if (isNum.matches()) {
            return true;
        } else {
            return false;
        }
    }

    /**
     * 判断字符串是否为日期格式
     *
     * @param strDate
     * @return boolean
     * @author nanning
     * @date 2019/9/20 13:57
     */
    public static boolean isStrDate(String strDate) {
        Matcher m = DATE_PATTERN.matcher(strDate);
        if (m.matches()) {
            return true;
        } else {
            return false;
        }
    }

    enum sexEnum {
        /**
         * 暂停
         */
        FEMALE("0"),
        /**
         * 正常
         */
        MALE("1");

        private String value;

        sexEnum(String value) {
            this.value = value;
        }

        public String value() {
            return value;
        }
    }

}
